import tkinter as tk
from tkinter import ttk, messagebox, simpledialog, filedialog
import pymysql
import csv
import re
from datetime import datetime
from decimal import Decimal


try:
    from admin import BankCardManagement, DepositManagement, TransactionManagement, CustomerManagement
    ADMIN_MODULES_AVAILABLE = True
except ImportError:
    ADMIN_MODULES_AVAILABLE = False

    pass

# 数据库配置
DB_CONFIG = {
    'host': 'localhost',
    'user': 'root',
    'password': '041128clxK',
    'database': '课设',
    'port': 3306
}

# ========== 数据库操作类 ==========
class Database:
    @staticmethod
    def connect():
        try:
            return pymysql.connect(
                host=DB_CONFIG['host'],
                user=DB_CONFIG['user'],
                password=DB_CONFIG['password'],
                database=DB_CONFIG['database'],
                port=DB_CONFIG['port'],
                cursorclass=pymysql.cursors.DictCursor
            )
        except pymysql.Error as e:
            messagebox.showerror("数据库错误", f"连接失败：{str(e)}")
            return None
    
    @staticmethod
    def execute_query(query, params=None):
        conn = Database.connect()
        if not conn:
            return None
        try:
            with conn.cursor() as cursor:
                cursor.execute(query, params or ())
                conn.commit()
                return cursor.rowcount
        except pymysql.Error as e:
            messagebox.showerror("数据库错误", f"操作失败：{str(e)}")
            conn.rollback()
        finally:
            if conn and conn.open:
                conn.close()
    
    @staticmethod
    def set_operation_context(operation_type, remark=""):
        """设置操作上下文，用于触发器判断操作类型"""
        conn = Database.connect()
        if not conn:
            return False
        try:
            with conn.cursor() as cursor:
                cursor.execute(
                    "INSERT INTO operation_context (connection_id, operation_type, remark) VALUES (CONNECTION_ID(), %s, %s)",
                    (operation_type, remark)
                )
                conn.commit()
                return True
        except pymysql.Error as e:
            print(f"设置操作上下文失败：{str(e)}")
            conn.rollback()
            return False
        finally:
            if conn and conn.open:
                conn.close()
    
    @staticmethod
    def fetch_one(query, params=None):
        conn = Database.connect()
        if not conn:
            return None
        try:
            with conn.cursor() as cursor:
                cursor.execute(query, params or ())
                return cursor.fetchone()
        except pymysql.Error as e:
            messagebox.showerror("数据库错误", f"查询失败：{str(e)}")
        finally:
            if conn and conn.open:
                conn.close()
    
    @staticmethod
    def fetch_all(query, params=None):
        conn = Database.connect()
        if not conn:
            return None
        try:
            with conn.cursor() as cursor:
                cursor.execute(query, params or ())
                return cursor.fetchall()
        finally:
            if conn and conn.open:
                conn.close()

# ========== 客户界面 ==========
class CustomerInterface:
    def __init__(self, root, username):
        self.root = root
        self.username = username
        self.root.title(f"客户界面 - {username}")
        self.root.geometry("800x600")
        
        # 界面色彩配置
        self.root.configure(bg="#E6F7FF")
        self.btn_bg = "#2196F3"
        self.danger_btn_bg = "#F44336"
        self.btn_fg = "white"
        self.font = ("SimHei", 12)
        
        self.create_widgets()
        self.load_customer_data()

    def load_customer_data(self):
        # 获取客户ID
        customer = Database.fetch_one("SELECT customerID FROM userinfo WHERE customerName = %s", (self.username,))
        if not customer:
            messagebox.showerror("错误", "未找到客户信息")
            return
        
        self.customer_id = customer['customerID']
        
        # 获取银行卡信息
        query = """
        SELECT c.cardID, c.balance, c.IsReportLoss, d.savingName, c.openDate 
        FROM cardinfo c
        LEFT JOIN deposit d ON c.savingID = d.savingID
        WHERE c.customerID = %s
        """
        self.cards = Database.fetch_all(query, (self.customer_id,))
        
        # 更新表格显示
        self.card_tree.delete(*self.card_tree.get_children())
        if self.cards:
            for card in self.cards:
                # 确保挂失状态正确显示
                loss_status = str(card['IsReportLoss']).strip()
                # 标准化显示格式
                if loss_status == '是' or loss_status == '1' or loss_status.upper() == 'TRUE':
                    display_status = '是'
                else:
                    display_status = '否'
                    
                self.card_tree.insert("", tk.END, values=(
                    card['cardID'],
                    card['savingName'],
                    f"{card['balance']:.2f}",
                    display_status,
                    card['openDate'].strftime('%Y-%m-%d')
                ))
        
        # 强制刷新界面
        self.card_tree.update()
        self.root.update_idletasks()

    def create_widgets(self):
        # 顶部标题
        title_frame = tk.Frame(self.root, bg="#E6F7FF")
        title_frame.pack(fill=tk.X, padx=20, pady=20)
        
        tk.Label(
            title_frame,
            text=f"欢迎，{self.username}",
            font=("SimHei", 16, "bold"),
            bg="#E6F7FF",
            fg="#333333"
        ).pack(side=tk.LEFT)

        # 功能按钮区域
        btn_frame = tk.Frame(self.root, bg="#E6F7FF")
        btn_frame.pack(fill=tk.X, padx=20, pady=10)
        
        buttons = [
            ("余额查询", self.check_balance),
            ("转账", self.transfer_money),
            ("存款", self.deposit_money),
            ("取款", self.withdraw_money),
            ("交易记录", self.show_transaction_history),
            ("统计分析", self.show_statistics),
            ("修改密码", self.change_password),
            ("挂失/解挂", self.toggle_loss)
        ]
        
        for i, (text, command) in enumerate(buttons):
            tk.Button(
                btn_frame,
                text=text,
                command=command,
                bg=self.btn_bg,
                fg=self.btn_fg,
                font=self.font,
                padx=15,
                pady=5,
                relief="flat"
            ).grid(row=0, column=i, padx=5)

        # 注销银行卡按钮（红色）
        tk.Button(
            btn_frame,
            text="注销银行卡",
            command=self.cancel_card,
            bg=self.danger_btn_bg,
            fg="white",
            font=self.font,
            padx=15,
            pady=5,
            relief="flat"
        ).grid(row=0, column=len(buttons), padx=5)

        # 银行卡信息表格
        card_frame = tk.LabelFrame(self.root, text="我的银行卡", bg="#E6F7FF")
        card_frame.pack(fill=tk.BOTH, expand=True, padx=20, pady=10)
        
        columns = ("卡号", "存款类型", "余额", "挂失状态", "开户日期")
        self.card_tree = ttk.Treeview(card_frame, columns=columns, show="headings", height=8)
        
        for col in columns:
            self.card_tree.heading(col, text=col)
            if col == "开户日期":
                self.card_tree.column(col, width=150, anchor="center")
            else:
                self.card_tree.column(col, width=120, anchor="center")
        
        scrollbar = ttk.Scrollbar(card_frame, orient="vertical", command=self.card_tree.yview)
        scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
        self.card_tree.configure(yscrollcommand=scrollbar.set)
        
        self.card_tree.pack(fill=tk.BOTH, expand=True)

    def check_balance(self):
        if not hasattr(self, 'cards') or not self.cards:
            messagebox.showwarning("提示", "您还没有银行卡")
            return
            
        selected = self.card_tree.selection()
        if not selected:
            messagebox.showwarning("提示", "请先选择一张银行卡")
            return
            
        card_id = self.card_tree.item(selected[0], "values")[0]
        
        password = simpledialog.askstring("验证身份", "请输入银行卡密码：", show="*")
        if not password:
            return
            
        query = """
        SELECT c.balance, d.savingName, c.openDate, c.IsReportLoss
        FROM cardinfo c
        LEFT JOIN deposit d ON c.savingID = d.savingID
        WHERE c.cardID = %s AND c.pass = %s
        """
        card = Database.fetch_one(query, (card_id, password))
        
        if not card:
            messagebox.showerror("错误", "卡号或密码错误")
            return
            
        if card['IsReportLoss'] == '是':
            messagebox.showerror("错误", "该卡已挂失，无法进行余额查询")
            return
            
        info = f"卡号: {card_id}\n"
        info += f"存款类型: {card['savingName']}\n"
        info += f"当前余额: {card['balance']:.2f}元\n"
        info += f"开户日期: {card['openDate'].strftime('%Y-%m-%d')}\n"
        info += f"状态: {'已挂失' if card['IsReportLoss'] == '是' else '正常'}"
        
        messagebox.showinfo("账户信息", info)

    def transfer_money(self):
        if not hasattr(self, 'cards') or not self.cards:
            messagebox.showwarning("提示", "您还没有银行卡")
            return
            
        selected = self.card_tree.selection()
        if not selected:
            messagebox.showwarning("提示", "请先选择转出银行卡")
            return
            
        from_card_id = self.card_tree.item(selected[0], "values")[0]
        
        password = simpledialog.askstring("验证身份", "请输入银行卡密码：", show="*")
        if not password:
            return
            
        from_card = Database.fetch_one(
            "SELECT IsReportLoss FROM cardinfo WHERE cardID = %s AND pass = %s",
            (from_card_id, password)
        )
        
        if not from_card:
            messagebox.showerror("错误", "卡号或密码错误")
            return
            
        if from_card['IsReportLoss'] == '是':
            messagebox.showerror("错误", "该卡已挂失，无法进行转账")
            return
            
        # 创建转账窗口
        self.create_transfer_window(from_card_id)

    def create_transfer_window(self, from_card_id):
        transfer_window = tk.Toplevel(self.root)
        transfer_window.title("转账")
        transfer_window.geometry("400x450")
        transfer_window.configure(bg="#E6F7FF")
        transfer_window.transient(self.root)
        transfer_window.grab_set()
        
        # 转出卡号显示
        tk.Label(
            transfer_window,
            text=f"转出卡号: {from_card_id}",
            font=self.font,
            bg="#E6F7FF",
            fg="#333333"
        ).pack(pady=10)
        
        # 转入卡号输入
        tk.Label(transfer_window, text="转入卡号:", font=self.font, bg="#E6F7FF").pack(pady=5)
        to_card_id_var = tk.StringVar(master=transfer_window)
        tk.Entry(transfer_window, textvariable=to_card_id_var, font=self.font, width=20).pack(pady=5)
        
        # 转账金额输入
        tk.Label(transfer_window, text="转账金额(元):", font=self.font, bg="#E6F7FF").pack(pady=5)
        money_var = tk.StringVar(master=transfer_window)
        tk.Entry(transfer_window, textvariable=money_var, font=self.font, width=20).pack(pady=5)
        
        # 交易密码输入
        tk.Label(transfer_window, text="交易密码:", font=self.font, bg="#E6F7FF").pack(pady=5)
        password_var = tk.StringVar(master=transfer_window)
        tk.Entry(transfer_window, textvariable=password_var, show="*", font=self.font, width=20).pack(pady=5)
        
        # 转账说明
        tk.Label(transfer_window, text="转账说明(可选):", font=self.font, bg="#E6F7FF").pack(pady=5)
        remark_var = tk.StringVar(master=transfer_window)
        tk.Entry(transfer_window, textvariable=remark_var, font=self.font, width=20).pack(pady=5)
        
        def do_transfer():
            to_card_id = to_card_id_var.get().strip()
            money_str = money_var.get().strip()
            password = password_var.get().strip()
            remark = remark_var.get().strip()
            
            if not to_card_id or not money_str or not password:
                messagebox.showerror("错误", "转入卡号、金额和密码不能为空")
                return
                
            try:
                money = Decimal(money_str)
                if money <= 0:
                    messagebox.showerror("错误", "转账金额必须大于0")
                    return
            except ValueError:
                messagebox.showerror("错误", "请输入有效的金额")
                return
                
            if not re.match(r'^\d{16}$', to_card_id):
                messagebox.showerror("错误", "转入卡号必须为16位数字")
                return
                
            if from_card_id == to_card_id:
                messagebox.showerror("错误", "不能向自己的银行卡转账")
                return
                
            # 执行转账逻辑
            self.execute_transfer(from_card_id, to_card_id, money, password, remark, transfer_window)
        
        tk.Button(
            transfer_window,
            text="确认转账",
            command=do_transfer,
            bg="#4CAF50",
            fg="white",
            font=self.font,
            padx=15,
            pady=5,
            relief="flat"
        ).pack(pady=20)

    def execute_transfer(self, from_card_id, to_card_id, money, password, remark, window):
        conn = Database.connect()
        if not conn:
            return
            
        try:
            with conn.cursor() as cursor:
                conn.begin()
                
                # 验证转出卡
                cursor.execute(
                    "SELECT balance, IsReportLoss FROM cardinfo WHERE cardID = %s AND pass = %s",
                    (from_card_id, password)
                )
                from_card = cursor.fetchone()
                
                if not from_card:
                    messagebox.showerror("错误", "转出卡密码错误")
                    return
                    
                if from_card['IsReportLoss'] == '是':
                    messagebox.showerror("错误", "转出卡已挂失")
                    return
                    
                if from_card['balance'] < money:
                    messagebox.showerror("错误", f"余额不足，当前余额: {from_card['balance']:.2f}元")
                    return
                    
                # 验证转入卡
                cursor.execute("SELECT balance, IsReportLoss FROM cardinfo WHERE cardID = %s", (to_card_id,))
                to_card = cursor.fetchone()
                
                if not to_card:
                    messagebox.showerror("错误", "转入卡号不存在")
                    return
                    
                if to_card['IsReportLoss'] == '是':
                    messagebox.showerror("错误", "转入卡已挂失")
                    return
                    
                # 执行转账 - 设置转出操作上下文
                cursor.execute(
                    "INSERT INTO operation_context (connection_id, operation_type, remark) VALUES (CONNECTION_ID(), %s, %s)",
                    ("transfer_out", f"转账给{to_card_id[:4]}****{to_card_id[-4:]}")
                )
                
                new_from_balance = from_card['balance'] - money
                cursor.execute(
                    "UPDATE cardinfo SET balance = %s WHERE cardID = %s",
                    (new_from_balance, from_card_id)
                )
                
                # 设置转入操作上下文
                cursor.execute(
                    "INSERT INTO operation_context (connection_id, operation_type, remark) VALUES (CONNECTION_ID(), %s, %s)",
                    ("transfer_in", f"接收来自{from_card_id[:4]}****{from_card_id[-4:]}的转账")
                )
                
                new_to_balance = to_card['balance'] + money
                cursor.execute(
                    "UPDATE cardinfo SET balance = %s WHERE cardID = %s",
                    (new_to_balance, to_card_id)
                )
                
                conn.commit()
                messagebox.showinfo("成功", f"转账{money}元成功！")
                window.destroy()
                self.load_customer_data()
                self.check_auto_cancel_after_operation()
                
        except pymysql.Error as e:
            conn.rollback()
            messagebox.showerror("数据库错误", f"转账失败：{str(e)}")
        finally:
            if conn and conn.open:
                conn.close()

    def deposit_money(self):
        self.money_operation("存款", "存入", "#4CAF50")

    def withdraw_money(self):
        self.money_operation("取款", "支取", "#FF5722")

    def money_operation(self, operation_name, trade_type, button_color):
        if not hasattr(self, 'cards') or not self.cards:
            messagebox.showwarning("提示", "您还没有银行卡")
            return
            
        selected = self.card_tree.selection()
        if not selected:
            messagebox.showwarning("提示", "请先选择一张银行卡")
            return
            
        card_id = self.card_tree.item(selected[0], "values")[0]
        
        password = simpledialog.askstring("验证身份", "请输入银行卡密码：", show="*")
        if not password:
            return
            
        card = Database.fetch_one(
            "SELECT IsReportLoss FROM cardinfo WHERE cardID = %s AND pass = %s",
            (card_id, password)
        )
        
        if not card:
            messagebox.showerror("错误", "卡号或密码错误")
            return
            
        if card['IsReportLoss'] == '是':
            messagebox.showerror("错误", f"该卡已挂失，无法进行{operation_name}")
            return
            
        self.create_money_operation_window(card_id, operation_name, trade_type, button_color)

    def create_money_operation_window(self, card_id, operation_name, trade_type, button_color):
        window = tk.Toplevel(self.root)
        window.title(operation_name)
        window.geometry("400x350")
        window.configure(bg="#E6F7FF")
        window.transient(self.root)
        window.grab_set()
        
        tk.Label(window, text=f"{operation_name}卡号: {card_id}", font=self.font, bg="#E6F7FF").pack(pady=10)
        
        tk.Label(window, text=f"{operation_name}金额(元):", font=self.font, bg="#E6F7FF").pack(pady=5)
        money_var = tk.StringVar(master=window)
        tk.Entry(window, textvariable=money_var, font=self.font, width=20).pack(pady=5)
        
        tk.Label(window, text="交易密码:", font=self.font, bg="#E6F7FF").pack(pady=5)
        password_var = tk.StringVar(master=window)
        tk.Entry(window, textvariable=password_var, show="*", font=self.font, width=20).pack(pady=5)
        
        tk.Label(window, text=f"{operation_name}说明(可选):", font=self.font, bg="#E6F7FF").pack(pady=5)
        remark_var = tk.StringVar(master=window)
        tk.Entry(window, textvariable=remark_var, font=self.font, width=20).pack(pady=5)
        
        def do_operation():
            money_str = money_var.get().strip()
            password = password_var.get().strip()
            remark = remark_var.get().strip()
            
            if not money_str or not password:
                messagebox.showerror("错误", f"{operation_name}金额和密码不能为空")
                return
                
            try:
                money = Decimal(money_str)
                if money <= 0:
                    messagebox.showerror("错误", f"{operation_name}金额必须大于0")
                    return
            except ValueError:
                messagebox.showerror("错误", "请输入有效的金额")
                return
                
            self.execute_money_operation(card_id, money, password, trade_type, remark, window, operation_name)
        
        tk.Button(
            window,
            text=f"确认{operation_name}",
            command=do_operation,
            bg=button_color,
            fg="white",
            font=self.font,
            padx=15,
            pady=5,
            relief="flat"
        ).pack(pady=20)

    def execute_money_operation(self, card_id, money, password, trade_type, remark, window, operation_name):
        conn = Database.connect()
        if not conn:
            return
            
        try:
            with conn.cursor() as cursor:
                conn.begin()
                
                cursor.execute(
                    "SELECT balance, IsReportLoss FROM cardinfo WHERE cardID = %s AND pass = %s",
                    (card_id, password)
                )
                card = cursor.fetchone()
                
                if not card:
                    messagebox.showerror("错误", "卡号或密码错误")
                    return
                    
                if card['IsReportLoss'] == '是':
                    messagebox.showerror("错误", f"该卡已挂失，无法进行{operation_name}")
                    return
                    
                if trade_type == "支取" and card['balance'] < money:
                    messagebox.showerror("错误", f"余额不足，当前余额: {card['balance']:.2f}元")
                    return
                    
                # 设置操作上下文
                operation_type = "deposit" if trade_type == "存入" else "withdraw"
                cursor.execute(
                    "INSERT INTO operation_context (connection_id, operation_type, remark) VALUES (CONNECTION_ID(), %s, %s)",
                    (operation_type, remark if remark else operation_name)
                )
                
                # 更新余额
                if trade_type == "存入":
                    new_balance = card['balance'] + money
                else:
                    new_balance = card['balance'] - money
                    
                cursor.execute(
                    "UPDATE cardinfo SET balance = %s WHERE cardID = %s",
                    (new_balance, card_id)
                )
                
                conn.commit()
                messagebox.showinfo("成功", f"{operation_name}{money}元成功！")
                window.destroy()
                self.load_customer_data()
                self.check_auto_cancel_after_operation()
                
        except pymysql.Error as e:
            conn.rollback()
            messagebox.showerror("数据库错误", f"{operation_name}失败：{str(e)}")
        finally:
            if conn and conn.open:
                conn.close()

    def show_transaction_history(self):
        if not hasattr(self, 'cards') or not self.cards:
            messagebox.showwarning("提示", "您还没有银行卡")
            return
            
        selected = self.card_tree.selection()
        if not selected:
            messagebox.showwarning("提示", "请先选择一张银行卡")
            return
            
        card_id = self.card_tree.item(selected[0], "values")[0]
        
        password = simpledialog.askstring("验证身份", "请输入银行卡密码：", show="*")
        if not password:
            return
            
        # 验证密码
        if not Database.fetch_one("SELECT * FROM cardinfo WHERE cardID = %s AND pass = %s", (card_id, password)):
            messagebox.showerror("错误", "卡号或密码错误")
            return
            
        # 查询交易记录
        query = """
        SELECT tradeID, tradeDate, tradeType, tradeMoney, remark 
        FROM tradeinfo 
        WHERE cardID = %s 
        ORDER BY tradeDate DESC
        """
        transactions = Database.fetch_all(query, (card_id,))
        
        if not transactions:
            messagebox.showinfo("提示", "暂无交易记录")
            return
            
        # 创建交易记录窗口
        history_window = tk.Toplevel(self.root)
        history_window.title(f"{card_id} 交易记录")
        history_window.geometry("700x500")
        history_window.configure(bg="#E6F7FF")
        
        columns = ("交易ID", "交易时间", "交易类型", "交易金额(元)", "备注")
        tree = ttk.Treeview(history_window, columns=columns, show="headings", height=15)
        
        for col in columns:
            tree.heading(col, text=col)
            if col == "交易时间":
                tree.column(col, width=180, anchor="center")
            elif col == "备注":
                tree.column(col, width=200, anchor="center")
            else:
                tree.column(col, width=120, anchor="center")
        
        scrollbar = ttk.Scrollbar(history_window, orient="vertical", command=tree.yview)
        scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
        tree.configure(yscrollcommand=scrollbar.set)
        
        tree.pack(fill=tk.BOTH, expand=True, padx=20, pady=20)
        
        # 填充数据
        for trans in transactions:
            tree.insert("", tk.END, values=(
                trans['tradeID'], 
                trans['tradeDate'].strftime('%Y-%m-%d %H:%M:%S'), 
                trans['tradeType'], 
                f"{trans['tradeMoney']:.2f}", 
                trans['remark']
            ))

    def show_statistics(self):
        if not hasattr(self, 'cards') or not self.cards:
            messagebox.showwarning("提示", "您还没有银行卡")
            return
            
        selected = self.card_tree.selection()
        if not selected:
            messagebox.showwarning("提示", "请先选择一张银行卡")
            return
            
        card_id = self.card_tree.item(selected[0], "values")[0]
        
        password = simpledialog.askstring("验证身份", "请输入银行卡密码：", show="*")
        if not password:
            return
            
        # 验证密码
        if not Database.fetch_one("SELECT * FROM cardinfo WHERE cardID = %s AND pass = %s", (card_id, password)):
            messagebox.showerror("错误", "卡号或密码错误")
            return
            
        # 统计存入和支取
        query = """
        SELECT 
            SUM(CASE WHEN tradeType = '存入' THEN tradeMoney ELSE 0 END) AS deposit_total,
            COUNT(CASE WHEN tradeType = '存入' THEN 1 END) AS deposit_count,
            SUM(CASE WHEN tradeType = '支取' THEN tradeMoney ELSE 0 END) AS withdraw_total,
            COUNT(CASE WHEN tradeType = '支取' THEN 1 END) AS withdraw_count
        FROM tradeinfo 
        WHERE cardID = %s
        """
        stats = Database.fetch_one(query, (card_id,))
        
        deposit_total = stats['deposit_total'] or 0
        deposit_count = stats['deposit_count'] or 0
        withdraw_total = stats['withdraw_total'] or 0
        withdraw_count = stats['withdraw_count'] or 0
        
        info = f"卡号: {card_id}\n\n"
        info += "===== 存入统计 =====\n"
        info += f"总存入金额: {deposit_total:.2f}元\n"
        info += f"存入笔数: {deposit_count}笔\n\n"
        info += "===== 支取统计 =====\n"
        info += f"总支取金额: {withdraw_total:.2f}元\n"
        info += f"支取笔数: {withdraw_count}笔"
        
        messagebox.showinfo("交易统计", info)

    def change_password(self):
        if not hasattr(self, 'cards') or not self.cards:
            messagebox.showwarning("提示", "您还没有银行卡")
            return
            
        selected = self.card_tree.selection()
        if not selected:
            messagebox.showwarning("提示", "请先选择一张银行卡")
            return
            
        card_id = self.card_tree.item(selected[0], "values")[0]
        
        password_window = tk.Toplevel(self.root)
        password_window.title("修改密码")
        password_window.geometry("400x300")
        password_window.configure(bg="#E6F7FF")
        password_window.transient(self.root)
        password_window.grab_set()
        
        tk.Label(password_window, text="请输入原密码：", font=self.font, bg="#E6F7FF").pack(pady=5)
        old_password_var = tk.StringVar(master=password_window)
        tk.Entry(password_window, textvariable=old_password_var, show="*", font=self.font, width=20).pack(pady=5)
        
        tk.Label(password_window, text="请输入新密码(6位数字)：", font=self.font, bg="#E6F7FF").pack(pady=5)
        new_password_var = tk.StringVar(master=password_window)
        tk.Entry(password_window, textvariable=new_password_var, show="*", font=self.font, width=20).pack(pady=5)
        
        tk.Label(password_window, text="请再次输入新密码：", font=self.font, bg="#E6F7FF").pack(pady=5)
        confirm_password_var = tk.StringVar(master=password_window)
        tk.Entry(password_window, textvariable=confirm_password_var, show="*", font=self.font, width=20).pack(pady=5)
        
        def do_change_password():
            old_password = old_password_var.get().strip()
            new_password = new_password_var.get().strip()
            confirm_password = confirm_password_var.get().strip()
            
            if not old_password or not new_password or not confirm_password:
                messagebox.showerror("错误", "所有字段都不能为空")
                return
                
            if len(new_password) != 6 or not new_password.isdigit():
                messagebox.showerror("错误", "新密码必须是6位数字")
                return
                
            if new_password != confirm_password:
                messagebox.showerror("错误", "两次输入的新密码不一致")
                return
                
            # 验证原密码
            card = Database.fetch_one("SELECT IsReportLoss FROM cardinfo WHERE cardID = %s AND pass = %s", (card_id, old_password))
            if not card:
                messagebox.showerror("错误", "原密码错误")
                return
                
            if card['IsReportLoss'] == '是':
                messagebox.showerror("错误", "该卡已挂失，无法修改密码")
                return
                
            # 更新密码
            result = Database.execute_query("UPDATE cardinfo SET pass = %s WHERE cardID = %s", (new_password, card_id))
            if result:
                messagebox.showinfo("成功", "密码修改成功")
                password_window.destroy()
            else:
                messagebox.showerror("错误", "密码修改失败")
        
        tk.Button(
            password_window,
            text="确认修改",
            command=do_change_password,
            bg="#4CAF50",
            fg="white",
            font=self.font,
            padx=15,
            pady=5,
            relief="flat"
        ).pack(pady=20)

    def toggle_loss(self):
        if not hasattr(self, 'cards') or not self.cards:
            messagebox.showwarning("提示", "您还没有银行卡")
            return
            
        selected = self.card_tree.selection()
        if not selected:
            messagebox.showwarning("提示", "请先选择一张银行卡")
            return
            
        card_id = self.card_tree.item(selected[0], "values")[0]
        
        password = simpledialog.askstring("验证身份", "请输入银行卡密码：", show="*")
        if not password:
            return
            
        card = Database.fetch_one("SELECT IsReportLoss FROM cardinfo WHERE cardID = %s AND pass = %s", (card_id, password))
        if not card:
            messagebox.showerror("错误", "卡号或密码错误")
            return
            
        current_status = str(card['IsReportLoss']).strip()
        
        if current_status == '是':
            confirm = messagebox.askyesno("确认", "该卡已挂失，确定要解挂吗？")
            if confirm:
                result = Database.execute_query("UPDATE cardinfo SET IsReportLoss = '否' WHERE cardID = %s", (card_id,))
                if result:
                    messagebox.showinfo("成功", "银行卡解挂成功")
                    self.load_customer_data()  # 重新加载数据
                else:
                    messagebox.showerror("错误", "解挂失败")
        else:
            confirm = messagebox.askyesno("确认", "确定要挂失该银行卡吗？")
            if confirm:
                result = Database.execute_query("UPDATE cardinfo SET IsReportLoss = '是' WHERE cardID = %s", (card_id,))
                if result:
                    messagebox.showinfo("成功", "银行卡挂失成功")
                    self.load_customer_data()  # 重新加载数据
                else:
                    messagebox.showerror("错误", "挂失失败")

    def cancel_card(self):
        if not hasattr(self, 'cards') or not self.cards:
            messagebox.showwarning("提示", "您还没有银行卡")
            return
            
        selected = self.card_tree.selection()
        if not selected:
            messagebox.showwarning("提示", "请先选择一张银行卡")
            return
            
        card_id = self.card_tree.item(selected[0], "values")[0]
        card_balance = float(self.card_tree.item(selected[0], "values")[2])
        
        if card_balance > 0:
            messagebox.showerror("错误", "银行卡余额必须为0才能注销！")
            return
            
        password = simpledialog.askstring("验证身份", "请输入银行卡密码：", show="*")
        if not password:
            return
            
        card = Database.fetch_one(
            "SELECT IsReportLoss FROM cardinfo WHERE cardID = %s AND pass = %s",
            (card_id, password)
        )
        
        if not card:
            messagebox.showerror("错误", "卡号或密码错误")
            return
            
        if card['IsReportLoss'] == '是':
            messagebox.showerror("错误", "该卡已挂失，无法注销")
            return
            
        confirm = messagebox.askyesno("危险操作", f"确定要注销卡号 {card_id} 吗？\n此操作不可恢复！")
        if not confirm:
            return
            
        # 删除银行卡和相关交易记录
        Database.execute_query("DELETE FROM tradeinfo WHERE cardID = %s", (card_id,))
        result = Database.execute_query("DELETE FROM cardinfo WHERE cardID = %s", (card_id,))
        
        if result:
            messagebox.showinfo("成功", "银行卡注销成功！")
            self.load_customer_data()
            self.check_auto_cancel_after_operation()

    def check_auto_cancel_after_operation(self):
        # 检查是否需要自动销户
        query = "SELECT SUM(balance) as total_balance FROM cardinfo WHERE customerID = %s"
        balance_result = Database.fetch_one(query, (self.customer_id,))
        total_balance = balance_result['total_balance'] or 0
        
        if total_balance < 1.0:
            messagebox.showinfo("自动销户", "检测到账户余额不足1元，将自动执行销户操作")
            self.perform_auto_cancel_account()

    def perform_auto_cancel_account(self):
        # 执行自动销户
        conn = Database.connect()
        if not conn:
            return
            
        try:
            with conn.cursor() as cursor:
                conn.begin()
                
                # 删除银行卡
                cursor.execute("DELETE FROM cardinfo WHERE customerID = %s", (self.customer_id,))
                
                # 删除交易记录
                cursor.execute(
                    "DELETE FROM tradeinfo WHERE cardID IN (SELECT cardID FROM cardinfo WHERE customerID = %s)", 
                    (self.customer_id,)
                )
                
                # 删除用户信息
                cursor.execute("DELETE FROM userinfo WHERE customerID = %s", (self.customer_id,))
                
                conn.commit()
                messagebox.showinfo("成功", "账号已自动注销！")
                self.root.destroy()
                
        except pymysql.Error as e:
            conn.rollback()
            messagebox.showerror("数据库错误", f"自动销户失败：{str(e)}")
        finally:
            if conn and conn.open:
                conn.close()



# ========== 角色选择界面 ==========
class RoleSelector:
    def __init__(self, root, username):
        self.root = root
        self.root.title("角色选择")
        self.root.geometry("400x350")
        self.root.resizable(False, False)
        self.username = username
        
        # 界面色彩配置
        self.root.configure(bg="#E6F7FF") 
        self.btn_bg = "#66CCFF"
        self.btn_fg = "white"
        self.danger_btn_bg = "#F44336"
        self.font = ("SimHei", 12)
        
        self.create_widgets()  

    def create_widgets(self):
        # 标题
        title_label = tk.Label(
            self.root, 
            text=f"欢迎，{self.username}！请选择角色", 
            font=("SimHei", 14, "bold"),
            bg="#E6F7FF",
            fg="#333333"
        )
        title_label.place(relx=0.5, rely=0.2, anchor=tk.CENTER)  

        # 按钮容器
        btn_frame = tk.Frame(self.root, bg="#E6F7FF")
        btn_frame.place(relx=0.5, rely=0.45, anchor=tk.CENTER)

        # 普通用户按钮
        tk.Button(
            btn_frame, 
            text="普通用户", 
            command=self.open_normal_user,
            bg=self.btn_bg,
            fg=self.btn_fg,
            font=self.font,
            padx=15,
            pady=5,
            relief="flat",
            cursor="hand2"
        ).grid(row=0, column=0, padx=10)

        # 管理员按钮
        tk.Button(
            btn_frame, 
            text="管理员", 
            command=self.verify_admin,
            bg=self.btn_bg,
            fg=self.btn_fg,
            font=self.font,
            padx=15,
            pady=5,
            relief="flat",
            cursor="hand2"
        ).grid(row=0, column=1, padx=10)

        # 销户按钮（红色）
        tk.Button(
            self.root, 
            text="销户", 
            command=self.cancel_account,
            bg=self.danger_btn_bg,
            fg="white",
            font=self.font,
            padx=15,
            pady=5,
            relief="flat",
            cursor="hand2"
        ).place(relx=0.5, rely=0.7, anchor=tk.CENTER)

    def verify_admin(self):
        pwd = simpledialog.askstring("管理员验证", "请输入管理员密码：", show="*")
        if pwd == "88888888":  
            self.open_admin()
        else:
            messagebox.showerror("错误", "密码不正确！")

    def open_normal_user(self):
        self.root.withdraw()
        new_root = tk.Tk()
        CustomerInterface(new_root, self.username)
        new_root.protocol("WM_DELETE_WINDOW", lambda: self.on_window_close(new_root))
        new_root.mainloop()

    def open_admin(self):
        self.root.withdraw()
        self.open_admin_interface()

    def open_admin_interface(self):
        new_root = tk.Tk()
        new_root.title("管理员界面")
        new_root.geometry("500x400")
        new_root.configure(bg="#E6F7FF")
        
        tk.Label(
            new_root, 
            text="管理员功能选择", 
            font=("SimHei", 16, "bold"),
            bg="#E6F7FF",
            fg="#333333"
        ).pack(pady=30)
        
        func_frame = tk.Frame(new_root, bg="#E6F7FF")
        func_frame.pack(pady=20)
        
        functions = [
            ("客户管理", self.open_customer_management),
            ("银行卡管理", self.open_bank_card_management),
            ("存款业务管理", self.open_deposit_management),
            ("交易管理", self.open_transaction_management)
        ]
        
        for i, (text, command) in enumerate(functions):
            row = i // 2
            col = i % 2
            
            tk.Button(
                func_frame, 
                text=text, 
                command=lambda cmd=command, w=new_root: self.execute_admin_function(cmd, w),
                bg=self.btn_bg,
                fg=self.btn_fg,
                font=self.font,
                padx=15,
                pady=5,
                relief="flat",
                cursor="hand2",
                width=12  
            ).grid(row=row, column=col, padx=15, pady=15)
        
        new_root.protocol("WM_DELETE_WINDOW", lambda: self.on_window_close(new_root))

    def execute_admin_function(self, command, parent_window):
        if not ADMIN_MODULES_AVAILABLE:
            messagebox.showerror("错误", "管理员模块不可用，请检查admin.py文件")
            return
            
        try:
            if command == self.open_customer_management:
                customer_window = tk.Toplevel(parent_window)
                # 确保正确导入和创建CustomerManagement实例
                from admin import CustomerManagement
                CustomerManagement(customer_window, self.username)
            else:
                command()
        except Exception as e:
            messagebox.showerror("错误", f"打开管理功能时发生错误：{str(e)}")

    def open_customer_management(self):
        if not ADMIN_MODULES_AVAILABLE:
            messagebox.showerror("错误", "客户管理功能不可用，请检查admin.py文件")
            return
        try:
            customer_window = tk.Toplevel()
            # 确保正确导入和创建CustomerManagement实例
            from admin import CustomerManagement
            CustomerManagement(customer_window, self.username)
        except Exception as e:
            messagebox.showerror("错误", f"打开客户管理功能时发生错误：{str(e)}")

    def open_bank_card_management(self):
        if not ADMIN_MODULES_AVAILABLE:
            messagebox.showerror("错误", "银行卡管理功能不可用，请检查admin.py文件")
            return
        try:
            bank_card_window = tk.Toplevel()
            # 确保正确导入和创建BankCardManagement实例
            from admin import BankCardManagement
            BankCardManagement(bank_card_window, self.username)
        except Exception as e:
            messagebox.showerror("错误", f"银行卡管理功能启动失败：{str(e)}")

    def open_deposit_management(self):
        if not ADMIN_MODULES_AVAILABLE:
            messagebox.showerror("错误", "存款业务管理功能不可用，请检查admin.py文件")
            return
        try:
            deposit_window = tk.Toplevel()
            # 确保正确导入和创建DepositManagement实例
            from admin import DepositManagement
            DepositManagement(deposit_window, self.username)
        except Exception as e:
            messagebox.showerror("错误", f"存款业务管理功能启动失败：{str(e)}")

    def open_transaction_management(self):
        if not ADMIN_MODULES_AVAILABLE:
            messagebox.showerror("错误", "交易管理功能不可用，请检查admin.py文件")
            return
        try:
            transaction_window = tk.Toplevel()
            # 确保正确导入和创建TransactionManagement实例
            from admin import TransactionManagement
            TransactionManagement(transaction_window, self.username)
        except Exception as e:
            messagebox.showerror("错误", f"交易管理功能启动失败：{str(e)}")

    def on_window_close(self, window):
        window.destroy()
        self.root.deiconify()

    def cancel_account(self):
        # 检查是否满足自动销户条件
        if self.check_auto_cancel_condition():
            messagebox.showinfo("自动销户", "检测到账户余额不足1元，将自动执行销户操作")
            self.perform_cancel_account()
            return
            
        # 手动销户确认
        confirm = messagebox.askyesno("危险操作", f"确定要注销{self.username}的账号吗？\n此操作将删除所有相关数据且不可恢复！")
        if not confirm:
            return
            
        self.perform_cancel_account()

    def check_auto_cancel_condition(self):
        # 获取客户ID
        customer = Database.fetch_one("SELECT customerID FROM userinfo WHERE customerName = %s", (self.username,))
        if not customer:
            return False
            
        customer_id = customer['customerID']
        
        # 查询所有银行卡余额
        balance_result = Database.fetch_one(
            "SELECT SUM(balance) as total_balance FROM cardinfo WHERE customerID = %s", 
            (customer_id,)
        )
        total_balance = balance_result['total_balance'] or 0
        
        return total_balance < 1.0

    def perform_cancel_account(self):
        # 获取客户ID
        customer = Database.fetch_one("SELECT customerID FROM userinfo WHERE customerName = %s", (self.username,))
        if not customer:
            messagebox.showerror("错误", "未找到用户信息")
            return
            
        customer_id = customer['customerID']
        
        conn = Database.connect()
        if not conn:
            return
            
        try:
            with conn.cursor() as cursor:
                conn.begin()
                
                # 删除交易记录
                cursor.execute(
                    "DELETE FROM tradeinfo WHERE cardID IN (SELECT cardID FROM cardinfo WHERE customerID = %s)", 
                    (customer_id,)
                )
                
                # 删除银行卡
                cursor.execute("DELETE FROM cardinfo WHERE customerID = %s", (customer_id,))
                
                # 删除用户信息
                cursor.execute("DELETE FROM userinfo WHERE customerID = %s", (customer_id,))
                
                conn.commit()
                messagebox.showinfo("成功", "账号注销成功！")
                self.root.destroy()
                
        except pymysql.Error as e:
            conn.rollback()
            messagebox.showerror("数据库错误", f"销户失败：{str(e)}")
        finally:
            if conn and conn.open:
                conn.close()

# ========== 登录注册界面 ==========
class AuthApp:
    def __init__(self, root):
        self.root = root
        self.root.title("银行管理系统 - 登录注册")
        self.root.geometry("500x500")
        self.root.resizable(False, False)
        
        # 界面色彩配置
        self.root.configure(bg="#F5F8FA")
        self.frame_bg = "#FFFFFF"
        self.label_fg = "#333333"
        self.btn_bg = "#66CCFF"
        self.btn_fg = "white"
        self.font = ("SimHei", 10)
        
        self.main_frame = tk.Frame(root, bg=self.frame_bg)
        self.main_frame.pack(fill=tk.BOTH, expand=True)
        
        self.show_login()

    def show_login(self):
        for widget in self.main_frame.winfo_children():
            widget.destroy()
        
        # 标题
        title_label = tk.Label(
            self.main_frame, 
            text="银行管理系统\n用户登录", 
            font=("SimHei", 16, "bold"),
            bg=self.frame_bg,
            fg=self.label_fg
        )
        title_label.place(relx=0.5, rely=0.2, anchor=tk.CENTER)

        # 用户名输入区域
        username_frame = tk.Frame(self.main_frame, bg=self.frame_bg)
        username_frame.place(relx=0.5, rely=0.35, anchor=tk.CENTER)
        tk.Label(
            username_frame, 
            text="用户名:", 
            font=self.font,
            bg=self.frame_bg,
            fg=self.label_fg
        ).pack(side=tk.LEFT, padx=10)
        self.login_username = tk.Entry(
            username_frame, 
            width=25,
            font=self.font,
            bd=1,
            relief="solid",
            highlightcolor=self.btn_bg,
            highlightthickness=1
        )
        self.login_username.pack(side=tk.LEFT, padx=10, fill=tk.X, expand=True)

        # 身份证号输入区域
        pid_frame = tk.Frame(self.main_frame, bg=self.frame_bg)
        pid_frame.place(relx=0.5, rely=0.45, anchor=tk.CENTER)
        tk.Label(
            pid_frame, 
            text="身份证号:", 
            font=self.font,
            bg=self.frame_bg,
            fg=self.label_fg
        ).pack(side=tk.LEFT, padx=10)
        self.login_pid = tk.Entry(
            pid_frame, 
            width=25,
            font=self.font,
            bd=1,
            relief="solid",
            highlightcolor=self.btn_bg,
            highlightthickness=1
        )
        self.login_pid.pack(side=tk.LEFT, padx=10, fill=tk.X, expand=True)

        # 登录按钮
        login_btn = tk.Button(
            self.main_frame, 
            text="登录", 
            command=self.handle_login,
            bg=self.btn_bg,
            fg=self.btn_fg,
            font=("SimHei", 12, "bold"),
            padx=15,
            pady=5,
            relief="flat",
            cursor="hand2"
        )
        login_btn.place(relx=0.5, rely=0.6, anchor=tk.CENTER)

        # 注册跳转标签
        register_label = tk.Label(
            self.main_frame, 
            text="还没账号？点击注册", 
            fg="#66CCFF", 
            cursor="hand2",
            bg=self.frame_bg,
            font=self.font
        )
        register_label.place(relx=0.5, rely=0.7, anchor=tk.CENTER)
        register_label.bind("<Button-1>", lambda e: self.show_register())

    def render_input(self, label_text, parent, var_name):
        frame = tk.Frame(parent, bg=self.frame_bg)
        frame.pack(fill=tk.X, pady=10)

        tk.Label(
            frame, 
            text=label_text, 
            font=self.font,
            bg=self.frame_bg,
            fg=self.label_fg
        ).pack(side=tk.LEFT, padx=10)

        entry = tk.Entry(
            frame, 
            width=25,
            font=self.font,
            bd=1,
            relief="solid",
            highlightcolor=self.btn_bg,
            highlightthickness=1
        )
        entry.pack(side=tk.LEFT, padx=10, fill=tk.X, expand=True)
        
        setattr(self, var_name, entry)

    def show_register(self):
        for widget in self.main_frame.winfo_children():
            widget.destroy()
        
        # 标题
        title_label = tk.Label(
            self.main_frame, 
            text="银行管理系统\n用户注册", 
            font=("SimHei", 16, "bold"),
            bg=self.frame_bg,
            fg=self.label_fg
        )
        title_label.place(relx=0.5, rely=0.15, anchor=tk.CENTER)

        # 表单区域
        form_frame = tk.Frame(self.main_frame, bg=self.frame_bg)
        form_frame.place(relx=0.5, rely=0.5, anchor=tk.CENTER)

        # 用户名输入
        self.render_input("用户名:", form_frame, "reg_username")
        # 身份证号输入
        self.render_input("身份证号:", form_frame, "reg_pid")
        # 联系电话输入
        self.render_input("联系电话:", form_frame, "reg_tel")
        # 联系地址输入
        self.render_input("联系地址:", form_frame, "reg_address")

        # 注册按钮
        register_btn = tk.Button(
            self.main_frame, 
            text="注册", 
            command=self.handle_register,
            bg=self.btn_bg,
            fg=self.btn_fg,
            font=("SimHei", 12, "bold"),
            padx=15,
            pady=5,
            relief="flat",
            cursor="hand2"
        )
        register_btn.place(relx=0.5, rely=0.75, anchor=tk.CENTER)

        # 登录跳转标签
        login_label = tk.Label(
            self.main_frame, 
            text="已有账号？点击登录", 
            fg="#66CCFF", 
            cursor="hand2",
            bg=self.frame_bg,
            font=self.font
        )
        login_label.place(relx=0.5, rely=0.85, anchor=tk.CENTER)
        login_label.bind("<Button-1>", lambda e: self.show_login())

    def handle_login(self):
        username = self.login_username.get().strip()
        pid = self.login_pid.get().strip()
        
        if not username or not pid:
            messagebox.showerror("错误", "用户名/身份证号不能为空！")
            return
        
        query = "SELECT customerName FROM userinfo WHERE customerName = %s AND PID = %s"
        result = Database.fetch_one(query, (username, pid))
        
        if result:
            messagebox.showinfo("成功", "登录成功！")
            self.root.destroy()  
            role_root = tk.Tk()
            RoleSelector(role_root, username)
            role_root.mainloop()
        else:
            messagebox.showerror("错误", "用户名或身份证号错误！")

    def handle_register(self):
        username = self.reg_username.get().strip()
        pid = self.reg_pid.get().strip()
        tel = self.reg_tel.get().strip()
        address = self.reg_address.get().strip()
        
        if not username or not pid or not tel:
            messagebox.showerror("错误", "用户名、身份证号和联系电话不能为空！")
            return
        
        if not re.match(r'^\d{17}[\dXx]$|^\d{15}$', pid):
            messagebox.showerror("错误", "身份证号格式不正确！")
            return
        
        if not re.match(r'^\d{11}$', tel):
            messagebox.showerror("错误", "联系电话格式不正确！")
            return
        
        # 检查身份证号是否已存在
        exists = Database.fetch_one("SELECT PID FROM userinfo WHERE PID = %s", (pid,))
        if exists:
            messagebox.showerror("错误", "该身份证号已注册！")
            return
        
        # 执行注册
        result = Database.execute_query(
            "INSERT INTO userinfo (customerName, PID, telephone, address) VALUES (%s, %s, %s, %s)",
            (username, pid, tel, address if address else None)
        )
        
        if result:
            messagebox.showinfo("成功", "注册成功！请登录")
            self.show_login()
        else:
            messagebox.showerror("错误", "注册失败！")




if __name__ == "__main__":
    root = tk.Tk()
    app = AuthApp(root)
    root.mainloop()
